/*
 * Copyright 2011-2012 Rivoli team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.rivoli.model.classhierarchy

import com.googlecode.rivoli.RivoliException
import com.googlecode.rivoli.model.Element
import com.googlecode.rivoli.model.ElementDescriptor
import com.googlecode.rivoli.model.classhierarchy.hierarchies.attributes.Report
import com.googlecode.rivoli.model.classhierarchy.hierarchies.containers.property.TableCell
import com.googlecode.rivoli.model.classhierarchy.hierarchies.containers.property.TableRow
import com.googlecode.rivoli.model.classhierarchy.hierarchies.parents.attributes.HorizontalOrientation
import com.googlecode.rivoli.model.classhierarchy.hierarchies.parents.attributes.Paragraph
import com.googlecode.rivoli.model.classhierarchy.hierarchies.parents.attributes.Structure
import com.googlecode.rivoli.model.classhierarchy.hierarchies.single.Letter
import com.googlecode.rivoli.model.support.ElementDescriptorSupport

import org.testng.annotations.Test

class ElementConverterTest {
	@Test
	void 'element without attributes should be convertible'() {
		Element element = new Element(new ClassBasedElementDescriptor(Letter))

		assert ElementConverter.convert(element, Letter)
	}

	@Test(expectedExceptions = RivoliException)
	void 'trying to convert element into non-matching type should cause exception'() {
		Element element = new Element(new ClassBasedElementDescriptor(Report))

		ElementConverter.convert(element, Letter)
	}

	@Test
	void 'element with attributes should be convertible'() {
		ElementDescriptorSupport elementDescriptor = new ClassBasedElementDescriptor(Report)
		elementDescriptor.addAttributeDescriptor('author', String)
		elementDescriptor.addAttributeDescriptor('date', Date)

		Element element = new Element(elementDescriptor)
		element.setAttribute('author', 'Rivoli team')
		element.setAttribute('date', Date.parse('d-M-yyyy', '30-12-2011'))

		Report report = ElementConverter.convert(element, Report)
		assert report.author == 'Rivoli team'
		assert report.date.format('d-M-yyyy') == '30-12-2011'
	}

	@Test(expectedExceptions = RivoliException)
	void 'trying to convert element with superfluous attributes should cause exception'() {
		ElementDescriptorSupport elementDescriptor = new ClassBasedElementDescriptor(Report)
		elementDescriptor.addAttributeDescriptor('title', String)

		Element element = new Element(elementDescriptor)
		element.setAttribute('title', 'Annual sales')

		ElementConverter.convert(element, Report)
	}

	@Test(expectedExceptions = RivoliException)
	void 'trying to convert element with attribute of unexpected type should cause exception'() {
		ElementDescriptorSupport elementDescriptor = new ClassBasedElementDescriptor(Report)
		elementDescriptor.addAttributeDescriptor('author', String)
		elementDescriptor.addAttributeDescriptor('date', String)

		Element element = new Element(elementDescriptor)
		element.setAttribute('author', 'Rivoli team')
		element.setAttribute('date', '30-12-2011')

		ElementConverter.convert(element, Report)
	}

	@Test
	void 'element with children should be convertible'() {
		ElementDescriptor tableCellDescriptor = new ClassBasedElementDescriptor(TableCell)
		ElementDescriptor tableRowDescriptor = new ClassBasedElementDescriptor(TableRow)
		tableRowDescriptor.containerFor = tableCellDescriptor

		Element element = new Element(tableRowDescriptor)
		element.addChild(new Element(tableCellDescriptor))
		element.addChild(new Element(tableCellDescriptor))

		TableRow tableRow = ElementConverter.convert(element, TableRow)

		assert tableRow.cells*.class == [TableCell, TableCell]
	}

	@Test
	void 'element with inherited attributes should be convertible'() {
		ElementDescriptorSupport structureDescriptor = new ClassBasedElementDescriptor(Structure)
		structureDescriptor.addAttributeDescriptor('horizontalAlignment', HorizontalOrientation)

		ElementDescriptor paragraphDescriptor = new ClassBasedElementDescriptor(Paragraph)
		paragraphDescriptor.parent = structureDescriptor

		Element element = new Element(paragraphDescriptor)
		element.setAttribute('horizontalAlignment', HorizontalOrientation.CENTER)

		Paragraph paragraph = ElementConverter.convert(element, Paragraph)
		assert paragraph.horizontalAlignment == HorizontalOrientation.CENTER
	}

	@Test
	void 'element reference should be stored on converted object'() {
		Element element = new Element(new ClassBasedElementDescriptor(Letter))

		Letter letter = ElementConverter.convert(element, Letter)

		assert letter.element == element
	}

	@Test(expectedExceptions = RivoliException)
	void 'element with element attribute should not be convertible'() {
		Element element = new Element(new ClassBasedElementDescriptor(com.googlecode.rivoli.model.classhierarchy.hierarchies.reference.Element))

		ElementConverter.convert(element, com.googlecode.rivoli.model.classhierarchy.hierarchies.reference.Element)
	}
}